iT邦幫忙

2024 iThome 鐵人賽

DAY 7
1
DevOps

全端監控技術筆記---從Sentry到Opentelemetry系列 第 7

Day07--如何在錯誤發生時、同時獲取user actions記錄

  • 分享至 

  • xImage
  •  

前言

在前幾篇中,我們嘗試自己獲取全局error、promise error、以及前端框架級別error(react error-boundary)。但就如同之前提到的---如果工程師只獲取error以及其console,不知道用戶是如何操作因而造成這個error的。根據我們之前的 demo,知道可以在Sentry平台中的Breadcrumbs中查看到user 在觸發 error前的一系列動作。

Sentry Breadcrumbs

Sentry中的Breadcrumbs,是用來記錄用戶一系列交互的機制,如點擊、輸入、頁面加載等等,這些操作會記錄在以一個類似log的array中,在程式發生異常的時候一起發送給Sentry。

在client side,Sentry SDK只會存100條breadcrumb 記錄(packages/core/src/scope.ts中有個const DEFAULT_MAX_BREADCRUMBS = 100;常量,限制了最多為100條)

獲取單個user-action

查看Sentry js SDK中的packages/browser-utils/src/instrument/dom.ts,可以知道Sentry會攔截user-event中的clickkeypress,並且賦予event_id、同時debounce,這樣一來可以透過檢查event_id的有無重複、以及在一定時間內只從同一個元素獲取event,來有效率的獲取user-action

至於要如何攔截?從 document.addEventListener('click', callback, true);入手,讓攔截器在事件捕獲階段就被監聽到。

事件的捕獲與冒泡

在browser的事件監聽機制中,分為三大階段:

  • 捕獲階段 (Capture Phase)
  • 目標階段 (Target Phase)
  • 冒泡階段 (Bubbling Phase)

image
from《What is Event Bubbling and Capturing and how to handle them?

而捕獲階段,事件會從全局(window)往下找尋找event相應的target。因此所有的事件都會從全局的捕獲階段開始,而如果是監聽冒泡階段的話,可能會被目標節點的父節點或者祖先節點給攔截(event.stopPropagation()),這樣一來就可能會監聽不到。這是為何要在全局事件捕獲階段掛載監聽器的原因。

解析dom

根據在 Sentry Breadcrumbs上的展示:

image

可以看到我們需要獲取該dom的節點路徑,如 body.vsc-initialized > div#root > div > div > button

這個邏輯,可以先獲取該event的target,然後在從其parentElement屬性,一層一層往上記錄:

cosnt getElementPath = (element) => {
        if (!element) return '';

        let path = [];

        while (element) {
            let name = element.nodeName.toLowerCase();
            if (element.id) {
                name += `#${element.id}`;
            } else if (element.className) {
                name += `.${element.className.split(' ').join('.')}`;
            }
            path.unshift(name);
            element = element.parentElement;
        }

        return path.join(' > ');
    };

基於 click 事件的user-actions記錄

先撇除debounce和事件id比較,直接利用上述的事件捕獲器和解析dom階段,寫一個
基於 click 事件的user-actions記錄:

  • self-instrument-dom.js
export class SelfDomInstrument {
    constructor() {
        this.userActions = [];
    }

    captureEvent(event) {
        if (event.type != 'click') return;

        const target = event.target;

        // TODO:檢查是否和上次catch的事件相似
        if (true) {
            const path = this._getElementPath(target);
            this.userActions.push({
                type: 'UI Click',
                time: new Date().toISOString(),
                path,
            });
        }
    }

    _getElementPath = (element) => {
        if (!element) return '';

        let path = [];

        while (element) {
            let name = element.nodeName.toLowerCase();
            if (element.id) {
                name += `#${element.id}`;
            } else if (element.className) {
                name += `.${element.className.split(' ').join('.')}`;
            }
            path.unshift(name);
            element = element.parentElement;
        }

        return path.join(' > ');
    };


    initEventMonintoring() {
        document.addEventListener('click', this.captureEvent.bind(this), true);
    }
}

有error的時候,打印user-actions

同樣,根據之前的全局error攔截器,我們可以加上window.onerror = callback的邏輯,在error發生的時候,打印出之前記錄的 user-actions:

    initEventMonintoring() {
        document.addEventListener('click', this.captureEvent.bind(this), true);
        window.onerror = this._errorHandler.bind(this);
    }

    _errorHandler(message, source, lineno, colno, error) {
        console.log('---user actions with error:', [
            ...this.userActions,
            {
                type: 'Error',
                time: new Date().toISOString(),
                message,
            },
        ]);
    }

實作結果

可以拿出之前的 InOrderError.jsx組件,順序點擊button,便可以在瀏覽器console中看到我們所記錄的user-actions 以及捕獲到的 error:

image

小結

我們知道了解了如何透過browser的事件捕獲階段、獲取全局的用戶事件,然後demo了監聽全局 click 事件,並且記錄下所有的user有使用click的target dom,在 error 發生的時候能夠打印所有的 user click actions,進而了解了Sentry的 Breadcrumbs機制。

本文的程式碼可以在Github repository上查看。

ref

ChangeLog

  • 20240921--內文、圖片
  • 20240918--大綱

上一篇
Day06--Sentry是如何獲取error? 直接手寫看看(下)
下一篇
Day08--Sentry是如何獲取效能指標(上)---react-router
系列文
全端監控技術筆記---從Sentry到Opentelemetry30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言